﻿using Magicodes.ExporterAndImporter.Excel;
using NP.BPMReportPlatform.BPMPlatform;
using NP.BPMReportPlatform.DBHelper;
using NP.BPMReportPlatform.Entities.BPM_Business.LCZX;
using NP.BPMReportPlatform.Entities.BPM_Business;
using NP.BPMReportPlatform.MaterialMasterData.Dto;
using NP.BPMReportPlatform.Utilities;
using NP.BPMReportPlatform.Utils;
using NP.Enterprise.Utils.Http;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Microsoft.Extensions.Configuration;
using System.IO;
using RestSharp;
using Serilog;
using ICSharpCode.SharpZipLib.Zip;
using System.Linq;
using System.Text;
using NPOI.HSSF.Record;
using SqlSugar.Extensions;

namespace NP.BPMReportPlatform.MaterialMasterData
{
    public class LBDXListingApplicationService : BPMReportPlatformAppService, ILBDXListingApplicationService
    {
        private readonly SqlSugarClient _db;
        private readonly SqlSugarClient _dbPlatform;
        private readonly SqlSugarClient _dbEngine;
        private readonly IBPMUtilsAppService _bPMUtilsApp;
        private readonly IBPMPlatformAppService _iBPMPlatformApp;
        private readonly INPRestHttpHelper _nPRestHttp;
        private readonly IExcelImporter _importer;
        private readonly ILogger _logger;
        private string _downLoadUrl;

        public LBDXListingApplicationService(ISqlSugarAppService sqlSugarAppService, IBPMUtilsAppService bPMUtilsApp
            , IBPMPlatformAppService iBPMPlatformApp, INPRestHttpHelper nPRestHttp, IConfiguration configuration, IExcelImporter importer,
            ILogger logger)
        {
            _db = sqlSugarAppService.GetBusinessInstance();
            _dbPlatform = sqlSugarAppService.GetPlatformInstance();
            _dbEngine = sqlSugarAppService.GetEngineInstance();
            _bPMUtilsApp = bPMUtilsApp;
            _iBPMPlatformApp = iBPMPlatformApp;
            _nPRestHttp = nPRestHttp;
            _importer = importer;
            _logger = logger;

            _downLoadUrl = configuration["BPM:AttachmentDownLoadUrl"];
        }

        public async Task<PagedResultDto<LBDXListingApplicationDto>> GetAllAsync(LBDXListingApplicationInput input)
        {
            RefAsync<int> totalCount = 0;

            var listQueryable = GetQueryable(input);
            var listViewDto = await listQueryable.ToPageListAsync(input.PageIndex, input.PageSize, totalCount);
            var userId = await _iBPMPlatformApp.GetUserAsync(CurrentUser.UserName);
            listViewDto.ForEach(x =>
            {
                x.Url = _bPMUtilsApp.GetProcessUrl(x.InstanceNumber, userId);
            });

            //返回结果
            return new PagedResultDto<LBDXListingApplicationDto>()
            {
                TotalCount = totalCount,
                Items = listViewDto
            };
        }

        public async Task<List<LBDXListingApplicationDto>> ExportAsync(LBDXListingApplicationInput input)
        {
            var listQueryable = GetQueryable(input);
            var listViewDto = await listQueryable.ToListAsync();
            return listViewDto;
        }

        /// <summary>
        /// 获取Queryable(报表展现)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private ISugarQueryable<LBDXListingApplicationDto> GetQueryable(LBDXListingApplicationInput input)
        {
            var listQueryable = _db.Queryable<LBDXListingApplicationHeader, LBDXListingApplicationDetail
                , LBDXListingApplicationDetailChild, BusinessProcessesNew>(
                (x, d, c, b) => new JoinQueryInfos(JoinType.Left, x.Id == d.LBDXListingApplicationHeaderId,
                JoinType.Left, d.Id == SqlFunc.ToString(c.LBDXListingApplicationDetailId),
                JoinType.Left, x.InstanceNumber.Equals(b.InstanceId)))
                .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), (x, d, c, b) => x.InstanceNumber.Contains(input.InstanceNumber))
                .WhereIF(!input.OrderStatus.IsNullOrEmpty(), (x, d, c, b) => SqlFunc.ContainsArray(input.OrderStatus.ToArray(), b.ProcessStatusCode))
                .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), (x, d, c, b) => b.StartUserName.Equals(input.AddUserName))
                .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null, (x, d, c, b) => b.StartTime >= input.StartCreationTime && b.StartTime.AddDays(-1) <= input.EndCreationTime)
                .WhereIF(!string.IsNullOrWhiteSpace(input.ProjectName), (x, d, c, b) => x.ProjectName.Contains(input.ProjectName))
                .WhereIF(!string.IsNullOrWhiteSpace(input.ProductName), (x, d, c, b) => d.ProductName.Contains(input.ProductName))
                .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), (x, d, c, b) => d.MaterialCode.Contains(input.MaterialCode))
                .Select((x, d, c, b) => new LBDXListingApplicationDto
                {
                    InstanceNumber = x.InstanceNumber,
                    AddTime = b.StartTime == null ? "" : b.StartTime.ToString(DateFormatHelper.DateTimeFormat),
                    AddUserName = b.StartUserName,
                    OrderStatus = b.ProcessStatusName,
                    ProjectName = x.ProjectName,
                    DemandSource = x.DemandSource,
                    EstimatedListingArea = x.EstimatedListingArea,
                    EstimatedNumberClasses = x.EstimatedNumberClasses,
                    EstimatedNumberParticipations = x.EstimatedNumberParticipations,
                    ContainsNumberProducts = x.ContainsNumberProducts,
                    EstimatedTotalProjectCost = x.EstimatedTotalProjectCost,
                    EstimatedTotalSales = x.EstimatedTotalSales,
                    EarningsTotalEstimate = x.EarningsEstimate,
                    RMCCTotal = x.RMCC,
                    Reason = x.Reason,
                    ProjectPlanId = x.ProjectPlanId,
                    ProjectPlanName = x.ProjectPlanName,
                    ProductFrameworkId = x.ProductFrameworkId,
                    ProductFrameworkName = x.ProductFrameworkName,
                    ProjectPriceDetailsId = x.ProjectPriceDetailsId,
                    ProjectPriceDetailsName = x.ProjectPriceDetailsName,

                    ProductName = d.ProductName,
                    ClientCode = d.ClientCode,
                    ChargeTypeCode = d.ChargeTypeCode,
                    ProjectTeamAndSchoolCode = d.ProjectTeamAndSchoolCode,
                    CourseTypeCode = d.CourseTypeCode,
                    TeachWayCode = d.TeachWayCode,
                    StandardTeacherCount = d.StandardTeacherCount,
                    StandardStudentCount = d.StandardStudentCount,
                    Days = d.Days,
                    MaterialCode = d.MaterialCode,
                    PricingUnit = d.PricingUnit,
                    EstimatedProjectCost = d.EstimatedProjectCost,
                    EstimatedSales = d.EstimatedSales,
                    EarningsEstimate = d.EarningsEstimate,
                    RMCC = d.RMCC,

                    Key = d.Key,

                    StartDate = c.StartDate == null ? "" : c.StartDate.Value.ToString(DateFormatHelper.DateFormat),
                    EndDate = c.EndDate == null ? "" : c.EndDate.Value.ToString(DateFormatHelper.DateFormat),
                    Amount = c.StartDate == null ? d.Amount : c.Amount,

                    DemandSourceText = x.DemandSourceName,
                    ChargeTypeCodeText = d.ChargeTypeName,
                    ClientCodeText = d.ClientName,
                    ProjectTeamAndSchoolCodeText = d.ProjectTeamAndSchoolName,
                    CourseTypeCodeText = d.CourseTypeName,
                    TeachWayCodeText = d.TeachWayName,

                    EstimatedTotalHumanCost = x.EstimatedTotalHumanCost,
                    EstimatedTotalRMCCCost = x.EstimatedTotalRMCCCost,
                    EstimatedTotalSitesCost = x.EstimatedTotalSitesCost,

                    CourseNature = d.CourseNature,
                }).MergeTable().Distinct().OrderBy(x => x.InstanceNumber, OrderByType.Desc)
                .OrderBy(x => x.Key, OrderByType.Asc);
            return listQueryable;
        }

        public async Task<byte[]> DownLoadFiles(DownLoadFileInput input)
        {
            if (input.AttachmentList == null || !input.AttachmentList.Any())
            {
                throw new Exception("无效请求");
            }


            RestClient client = new RestClient();
            var fileList = new Dictionary<string, byte[]>();
            int index = 1;
            foreach (var file in input.AttachmentList)
            {
                var url = string.Format(_downLoadUrl, file.Id);
                var result = client.DownloadData(new RestRequest(url, Method.GET));
                if (result == null || !result.Any())
                {
                    continue;
                }

                fileList.Add($"{file.InstanceNumber}_{index}_{file.Name}", result);
                index++;
            }
            var stream = ZipFile(fileList);
            return stream.ToArray();
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="dic"></param>
        /// <returns></returns>
        public MemoryStream ZipFile(Dictionary<string, byte[]> dic)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            var gbk = Encoding.GetEncoding("GBK");
            ICSharpCode.SharpZipLib.Zip.ZipStrings.CodePage = gbk.CodePage;

            MemoryStream stream = new MemoryStream();
            using (ZipFile zip = new ZipFile(stream))
            {                
                zip.BeginUpdate();

                foreach (var item in dic)
                {
                    StringDataSource sd = new StringDataSource(item.Value);
                    zip.Add(sd, item.Key);
                }

                zip.CommitUpdate();
            }

            return stream;
        }

        /// <summary>
        /// 修复数据-那些编码字段补充名称数据，以兼容编码对应名称会变动的问题
        /// </summary>
        /// <returns></returns>
        public void FixData(string instanceNumber, bool isReUpdate = false)
        {
            if (!Int64.TryParse(instanceNumber, out Int64 instanceId))
            {
                return;
            }

            var headers = _db.Queryable<LBDXListingApplicationHeader>().Where(x => SqlFunc.ToInt64(x.InstanceNumber) <= instanceId).ToList();
            foreach (var header in headers)
            {
                if (string.IsNullOrEmpty(header.DemandSourceName) || isReUpdate)
                {
                    header.DemandSourceName = CodeToTextHelper.demandSourceClientCodeList.ContainsKey(header.DemandSource) ?
                        CodeToTextHelper.demandSourceClientCodeList[header.DemandSource] : "";
                }
            }
            _db.Updateable(headers).UpdateColumns(x => new { x.DemandSourceName }).ExecuteCommand();

            var details = _db.Queryable<LBDXListingApplicationDetail>().Where(x => SqlFunc.ToInt64(x.InstanceNumber) <= instanceId).ToList();
            foreach (var detail in details)
            {
                if (string.IsNullOrEmpty(detail.ClientName) || isReUpdate)
                {
                    detail.ClientName = CodeToTextHelper.demandSourceClientCodeList.ContainsKey(detail.ClientCode) ?
                        CodeToTextHelper.demandSourceClientCodeList[detail.ClientCode] : "";
                }
                if (string.IsNullOrEmpty(detail.ChargeTypeName) || isReUpdate)
                {
                    detail.ChargeTypeName = CodeToTextHelper.chargeTypeCodeList.ContainsKey(detail.ChargeTypeCode) ?
                        CodeToTextHelper.chargeTypeCodeList[detail.ChargeTypeCode] : "";
                }
                if (string.IsNullOrEmpty(detail.ProjectTeamAndSchoolName) || isReUpdate)
                {
                    detail.ProjectTeamAndSchoolName = CodeToTextHelper.projectTeamAndSchoolCodeList.ContainsKey(detail.ProjectTeamAndSchoolCode) ?
                        CodeToTextHelper.projectTeamAndSchoolCodeList[detail.ProjectTeamAndSchoolCode] : "";
                }
                if (string.IsNullOrEmpty(detail.CourseTypeName) || isReUpdate)
                {
                    detail.CourseTypeName = CodeToTextHelper.courseTypeCodeList.ContainsKey(detail.CourseTypeCode) ?
                        CodeToTextHelper.courseTypeCodeList[detail.CourseTypeCode] : "";
                }
                if (string.IsNullOrEmpty(detail.TeachWayName) || isReUpdate)
                {
                    detail.TeachWayName = CodeToTextHelper.teachWayCodeList.ContainsKey(detail.TeachWayCode) ?
                        CodeToTextHelper.teachWayCodeList[detail.TeachWayCode] : "";
                }
            }
            _db.Updateable(details).UpdateColumns(x => new
            {
                x.ClientName,
                x.ChargeTypeName,
                x.ProjectTeamAndSchoolName,
                x.CourseTypeName,
                x.TeachWayName
            }).ExecuteCommand();
        }
    }
}
